package com.youxin.logprocess.controller;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;

import org.apache.log4j.Logger;

import com.youxin.busfoundation.bean.MonitorMaxTimesBean;
import com.youxin.foundation.db.redis.RedisClusterCommand;
import com.youxin.foundation.utils.DateUtil;
import com.youxin.foundation.utils.JsonUtils;
import com.youxin.foundation.utils.StringUtils;
import com.youxin.foundation.utils.collections.CollectionsUtils;
import com.youxin.foundation.utils.thread.ScheduleThreadPool;
import com.youxin.foundation.utils.timer.TimerSchedule;
import com.youxin.logprocess.bean.MessageBean;
import com.youxin.logprocess.common.MonitorDateUtils;
import com.youxin.logprocess.common.MonitorGlobalConfig;
import com.youxin.logprocess.common.MonitorRedisKeyGenerator;

import redis.clients.jedis.JedisCluster;;

/**
 * 统计控制器
 * 
 * @author yingde.cao
 *
 */
public class StatController {
	private static StatController controller = new StatController();
	private List<BaseMonitorController> monitorControllers = new ArrayList<>(7);
	private static Logger logger = Logger.getLogger(MonitorZookeeperController.class);
	private MonitorMaxTimesBean messageMaxTimes;

	public static StatController instance() {
		return controller;
	}

	public static void initConfig(MonitorMaxTimesBean messageMaxTimes) {
		controller.setMessageMaxTimes(messageMaxTimes);
	}

	private LinkedBlockingDeque<Integer> queue = null;
	private Thread producerThread = null, consumerThread = null;
	private long latestTime = 0;
	private int capacity = 0;

	public MonitorMaxTimesBean getMessageMaxTimes() {
		return messageMaxTimes;
	}

	public void setMessageMaxTimes(MonitorMaxTimesBean messageMaxTimes) {
		this.messageMaxTimes = messageMaxTimes;
	}

	/**
	 * 添加监控的控制器,同步信息使用
	 * 
	 * @param monitorBaseController
	 */
	public void add(BaseMonitorController monitorBaseController) {
		if (monitorBaseController.getMonitorBean().getMonitor() == 1) {
			monitorControllers.add(monitorBaseController);
		}
	}

	public void execute() {
		if (messageMaxTimes == null) {
			throw new RuntimeException("请配置stat Config的值");
		}
		capacity = 60;
		queue = new LinkedBlockingDeque<>(capacity);
		producerQueue();
	}

	

	private void producerQueue() {	
		
		ScheduleThreadPool.scheduleWithFixedDelay(new Runnable() {			
			@Override
			public void run() {
				try {
					for (BaseMonitorController baseController : monitorControllers) {
						final String redisKey = baseController.getMonitorBean().getId();
						String lockKey = MonitorRedisKeyGenerator.lockKey(redisKey);
						RedisClusterCommand.instance().lockCommand(lockKey, 6000, (redisCluster) -> {
							try {
								/**
								 * 获取当前监控的异常信息
								 */
								List<MessageBean> beans = baseController.popAll();
								String tRedisKey = redisKey;
								Map<String, String> monitorRedisMap = redisCluster.hgetAll(tRedisKey);
								Map<String, String> resultValues = new HashMap<>(10);
								String value = monitorRedisMap.get(MonitorRedisKeyGenerator.INFO);

								List<MessageBean> redisBeans = getMessageBeanListByValue(value);
								/**
								 * 先取出以前的失败信息,如果为空就保存当前的信息,如果存在就合并
								 */
								int messageSize = redisBeans == null ? 0 : redisBeans.size();
								List<MessageBean> result = beans;
								if (messageSize > 0) {
									result = CollectionsUtils.combine(beans, redisBeans);
								}
								if (isCanSendMessasges(result, monitorRedisMap, resultValues)) {
									resultValues.put(MonitorRedisKeyGenerator.INFO, "");
									redisOperate(redisCluster, tRedisKey, monitorRedisMap, resultValues);
									baseController.sendMessages(result);
								} else {
									if (messageSize < result.size()) {
										value = JsonUtils.objectToJsonString(result);
										resultValues.put(MonitorRedisKeyGenerator.INFO, value);
										redisOperate(redisCluster, tRedisKey, monitorRedisMap, resultValues);
									}
								}

							} catch (Exception e) {
								logger.error("执行任务时异常:" + redisKey, e);
							}
						});
					}

				} catch (Exception e) {
					logger.error("producerQueue执行任务时异常", e);
				}
			}
		}, 4000, MonitorGlobalConfig.START_DELAY_TIME);

		
	}

	/**
	 * 更新Redis中的数据
	 * 
	 * @param redisCluster
	 * @param redisKey
	 * @param monitorRedisMap
	 * @param resultValues
	 */
	private void redisOperate(JedisCluster redisCluster, String redisKey, Map<String, String> monitorRedisMap,
			Map<String, String> resultValues) {
		redisCluster.hmset(redisKey, resultValues);
		/**
		 * 查找旧的统计数据,旧的统计数据需要删除
		 */
		List<String> delkeys = monitorRedisMap.keySet().stream().filter((item) -> {
			return !resultValues.containsKey(item);
		}).collect(Collectors.toList());
		if (delkeys.size() > 0) {
			String[] delkeyArray = delkeys.toArray(new String[] {});
			redisCluster.hdel(redisKey, delkeyArray);
		}
	}

	/**
	 * 判断是否符合发送邮件和短信的条件
	 * 
	 * @param monitorRedisMap
	 *            监控组所对应的redis HashMap的数据
	 * @param resultValues
	 *            保存监控组里面新的发送邮件短信的信息
	 * @return boolean 是否可以发送
	 */
	private boolean isCanSendMessasges(List<MessageBean> result, Map<String, String> monitorRedisMap,
			Map<String, String> resultValues) {
		if (result.size() == 0) {
			return false;
		}

		Date date = new Date();
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		String currentMinute = DateUtil.getFormatTime(calendar);
		calendar.setTime(date);
		String twentyMinute = MonitorDateUtils.getMinuteTwentyFormat(calendar);
		calendar.setTime(date);
		String hourMinute = MonitorDateUtils.getMinuteFormat(calendar, 60);

		String currentMinuteTimeKey = MonitorRedisKeyGenerator.minuteKey(currentMinute);
		String twentyMiuteTimeKey = MonitorRedisKeyGenerator.twentyKey(twentyMinute);
		String hourMinuteKey = MonitorRedisKeyGenerator.hourKey(hourMinute);

		long currentMinuteTimes = CollectionsUtils.getLongValue(monitorRedisMap, currentMinuteTimeKey);
		long twentyMinuteTimes = CollectionsUtils.getLongValue(monitorRedisMap, twentyMiuteTimeKey);
		long hourMinuteTimes = CollectionsUtils.getLongValue(monitorRedisMap, hourMinuteKey);

		resultValues.put(currentMinuteTimeKey, String.valueOf(currentMinuteTimes));
		resultValues.put(twentyMiuteTimeKey, String.valueOf(twentyMinuteTimes));
		resultValues.put(hourMinuteKey, String.valueOf(hourMinuteTimes));

		boolean success = true;
		if (currentMinuteTimes >= messageMaxTimes.getMinute()) {
			success = false;
		} else if (twentyMinuteTimes >= messageMaxTimes.getTwenty()) {
			success = false;
		} else if (hourMinuteTimes >= messageMaxTimes.getHour()) {
			success = false;
		}
		if (success) {
			++currentMinuteTimes;
			++twentyMinuteTimes;
			++hourMinuteTimes;
		}
		resultValues.put(currentMinuteTimeKey, String.valueOf(currentMinuteTimes));
		resultValues.put(twentyMiuteTimeKey, String.valueOf(twentyMinuteTimes));
		resultValues.put(hourMinuteKey, String.valueOf(hourMinuteTimes));
		return success;
	}

	/**
	 * 消息转换为List对象
	 * 
	 * @param value
	 *            json 字符串
	 * @return List<MessageBean>
	 */
	private List<MessageBean> getMessageBeanListByValue(String value) {
		try {
			if (StringUtils.isNullOrEmpty(value)) {
				return null;
			}
			return (List<MessageBean>) JsonUtils.stringToList(value, MessageBean.class);
		} catch (Exception e) {
			logger.error("value:" + value + "转换异常", e);
			return null;
		}
	}

}
